home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / CLASSSRC.PAK / DATE.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  10KB  |  364 lines

  1. //----------------------------------------------------------------------------
  2. // Borland Class Library
  3. // Copyright (c) 1993, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   5.6  $
  6. //
  7. // TDate class implementation
  8. //----------------------------------------------------------------------------
  9. #include <classlib/pch.h>
  10. #include <classlib/date.h>
  11. #include <services/cstring.h>
  12. #include <services/checks.h>
  13. #include <stdio.h>
  14. #include <time.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include <tchar.h>
  18.  
  19. /****************************************************************
  20.  *                                                              *
  21.  *                      static constants                        *
  22.  *                                                              *
  23.  ****************************************************************/
  24.  
  25. static const _TUCHAR DaysInMonth[12] =
  26.     { 31,28,31,30,31,30,31,31,30,31,30,31 };
  27. static const DayTy FirstDayOfEachMonth[12] =
  28.     { 1,32,60,91,121,152,182,213,244,274,305,335 };
  29. static const _TCHAR *MonthNames[12] =
  30.     { "January","February","March","April","May","June",
  31.       "July","August","September","October","November","December" };
  32. static const _TCHAR *UCMonthNames[12] =
  33.     { "JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE",
  34.       "JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER" };
  35. static const _TCHAR *WeekDayNames[7] =
  36.     { "Monday","Tuesday","Wednesday",
  37.       "Thursday","Friday","Saturday","Sunday" };
  38. static const _TCHAR *UCWeekDayNames[7] =
  39.     { "MONDAY","TUESDAY","WEDNESDAY",
  40.       "THURSDAY","FRIDAY","SATURDAY","SUNDAY" };
  41.  
  42. static int _BIDSNEARFUNC
  43. FindMatch( const _TCHAR *str, const _TCHAR**candidates, int icand );
  44.  
  45. /***************************************************************************/
  46.  
  47. //      constructors
  48.  
  49. /***************************************************************************/
  50.  
  51. //
  52. // Construct a TDate for today's date.
  53. //
  54. TDate::TDate()
  55. {
  56.     long clk = time(0);
  57.     struct tm _FAR *now = localtime(&clk);
  58.     Julnum = Jday(now->tm_mon+1, now->tm_mday, now->tm_year+1900);
  59. }
  60.  
  61. //
  62. // Construct a TDate with a given day of the year and a given year.  The
  63. // base date for this computation is Dec. 31 of the previous year.  If
  64. // year == 0, Construct a TDate with Jan. 1, 1901 as the "day zero".
  65. // i.e., TDate(-1) = Dec. 31, 1900 and TDate(1) = Jan. 2, 1901.
  66. //
  67. TDate::TDate(DayTy day, YearTy year)
  68. {
  69.     if( year )
  70.         Julnum = Jday( 12, 31, year-1 ) + (JulTy)day;
  71.     else
  72.         Julnum = jul1901                + (JulTy)day;
  73. }
  74.  
  75. //
  76. //   Construct a TDate for the given day, monthName, and year.
  77. //
  78. TDate::TDate( DayTy day, const _TCHAR _BIDSFAR *monthName, YearTy year )
  79. {
  80.     Julnum = Jday( IndexOfMonth(monthName), day, year );
  81. }
  82.  
  83. //
  84. //   Construct a TDate for the given day, month, and year.
  85. //
  86. TDate::TDate( DayTy day, MonthTy month, YearTy year )
  87. {
  88.     Julnum = Jday( month, day, year );
  89. }
  90.  
  91. /***************************************************************************/
  92.  
  93. //                      static member functions
  94.  
  95. /***************************************************************************/
  96.  
  97. //
  98. // Returns a string name for the weekday number.
  99. // Monday == 1, ... , Sunday == 7
  100. // Return 0 for weekday number out of range
  101. //
  102. const _TCHAR _BIDSFAR *TDate::DayName( DayTy weekDayNumber )
  103. {
  104.     return AssertWeekDayNumber(weekDayNumber) ? WeekDayNames[weekDayNumber-1] : 0;
  105. }
  106.  
  107. //
  108. // Return the number, 1-7, of the day of the week named nameOfDay.
  109. // Return 0 if name doesn't match.
  110. //
  111. DayTy TDate::DayOfWeek( const _TCHAR _BIDSFAR *nameOfDay )
  112. {
  113.     return (DayTy)(FindMatch( nameOfDay, UCWeekDayNames, 7 )+1);
  114. }
  115.  
  116. //
  117. // Is a day (1-31) within a given month?
  118. //
  119. int TDate::DayWithinMonth( MonthTy month, DayTy day, YearTy year )
  120. {
  121.     if( day <= 0 || !AssertIndexOfMonth(month) )
  122.         return 0;
  123.     unsigned d = DaysInMonth[month-1];
  124.     if( LeapYear(year) && month == 2 )
  125.         d++;
  126.     return day <= d;
  127. }
  128.  
  129. //
  130. // How many days are in the given YearTy year?
  131. //
  132. DayTy TDate::DaysInYear( YearTy year )
  133. {
  134.     return LeapYear(year) ? 366 : 365;
  135. }
  136.  
  137. //
  138. // Returns the number, 1-12, of the month named nameOfMonth.
  139. // Return 0 for no match.
  140. //
  141. MonthTy TDate::IndexOfMonth( const _TCHAR _BIDSFAR *nameOfMonth )
  142. {
  143.     return (MonthTy)(FindMatch( nameOfMonth, UCMonthNames, 12 )+1);
  144. }
  145.  
  146. //
  147. // Convert Gregorian calendar date to the corresponding Julian day
  148. // number j.  Algorithm 199 from Communications of the ACM, Volume 6, No.
  149. // 8, (Aug. 1963), p. 444.  Gregorian calendar started on Sep. 14, 1752.
  150. // This function not valid before that.
  151. // Returns 0 if the date is invalid.
  152. //
  153. JulTy TDate::Jday( MonthTy m, DayTy d, YearTy y )
  154. {
  155.     unsigned long c, ya;
  156.     if( y <= 99 )
  157.         y += 1900;
  158.     if( !DayWithinMonth(m, d, y) )
  159.         return (JulTy)0;
  160.  
  161.     if( m > 2 )
  162.         m -= 3;
  163.     else
  164.         {
  165.         m += 9;
  166.         y--;
  167.         }
  168.  
  169.     c = y / 100;
  170.     ya = y - 100*c;
  171.     return ((146097L*c)>>2) + ((1461*ya)>>2) + (153*m + 2)/5 + d + 1721119L;
  172. }
  173.  
  174. //
  175. // Algorithm from K & R, "The C Programming Language", 1st ed.
  176. //
  177. int TDate::LeapYear( YearTy year )
  178. {
  179.     return (year&3) == 0 && year%100 != 0 || year % 400 == 0;
  180. }
  181.  
  182. //
  183. // Returns a string name for the month number.
  184. // Return 0 if invalid month number.
  185. //
  186. const _TCHAR _BIDSFAR *TDate::MonthName( MonthTy monthNumber )
  187. {
  188.     return AssertIndexOfMonth(monthNumber) ? MonthNames[monthNumber-1] : 0;
  189. }
  190.  
  191. //
  192. // Return index of case-insensitive match; -1 if no match.
  193. //
  194. static int _BIDSNEARFUNC FindMatch( const _TCHAR *str, const _TCHAR**candidates, int icand )
  195. {
  196.     unsigned len = _tcslen(str);
  197.  
  198.     while(icand--)
  199.         {
  200.         if( _tcsnicmp(str, candidates[icand], len) == 0)
  201.             break;
  202.         }
  203.     return icand;
  204. }
  205.  
  206. /****************************************************************
  207.  *                                                              *
  208.  *                      Member functions                        *
  209.  *                                                              *
  210.  ****************************************************************/
  211.  
  212. //
  213. // Compare function:
  214. //
  215. int TDate::CompareTo( const TDate _BIDSFAR &d ) const
  216. {
  217.     if( Julnum < d.Julnum )
  218.         return -1;
  219.     else if( Julnum > d.Julnum )
  220.         return 1;
  221.     else
  222.         return 0;
  223. }
  224.  
  225. //
  226. //
  227. //
  228. DayTy TDate::Day() const
  229. {
  230.     return DayTy(Julnum - Jday( 12, 31, Year()-1 ));
  231. }
  232.  
  233. //
  234. // Returns the day of the month of this TDate.
  235. //
  236. DayTy TDate::DayOfMonth() const
  237. {
  238.     MonthTy m; DayTy d; YearTy y;
  239.     Mdy( m, d, y );
  240.     return d;
  241. }
  242.  
  243. //
  244. // Return the number of the first day of a given month
  245. // Return 0 if "month" is outside of the range 1 through 12, inclusive.
  246. //
  247. DayTy TDate::FirstDayOfMonth( MonthTy month ) const
  248. {
  249.     if ( !AssertIndexOfMonth(month) )
  250.         return 0;
  251.     unsigned firstDay = FirstDayOfEachMonth[month-1];
  252.     if (month > 2 && Leap())
  253.         firstDay++;
  254.     return firstDay;
  255. }
  256.  
  257. unsigned TDate::Hash() const
  258. {
  259.     return (unsigned)Julnum;
  260. }
  261.  
  262. //
  263. // Convert a Julian day number to its corresponding Gregorian calendar
  264. // date.  Algorithm 199 from Communications of the ACM, Volume 6, No. 8,
  265. // (Aug. 1963), p. 444.  Gregorian calendar started on Sep. 14, 1752.
  266. // This function not valid before that.
  267. //
  268. void _BIDSNEARFUNC TDate::Mdy( MonthTy _BIDSFAR & m, DayTy _BIDSFAR & D, YearTy _BIDSFAR & y ) const
  269. {
  270.     unsigned long d;
  271.     JulTy j = Julnum - 1721119L;
  272.     y = (YearTy) (((j<<2) - 1) / 146097L);
  273.     j = (j<<2) - 1 - 146097L*y;
  274.     d = (j>>2);
  275.     j = ((d<<2) + 3) / 1461;
  276.     d = (d<<2) + 3 - 1461*j;
  277.     d = (d + 4)>>2;
  278.     m = (MonthTy)(5*d - 3)/153;
  279.     d = 5*d - 3 - 153*m;
  280.     D = (DayTy)((d + 5)/5);
  281.     y = (YearTy)(100*y + j);
  282.  
  283.     if( m < 10 )
  284.         m += 3;
  285.     else
  286.         {
  287.         m -= 9;
  288.         y++;
  289.         }
  290. }
  291.  
  292. //
  293. //
  294. //
  295. TDate TDate::Max( const TDate _BIDSFAR & dt ) const
  296. {
  297.     return dt.Julnum > Julnum ? dt : *this;
  298. }
  299.  
  300. //
  301. //
  302. //
  303. TDate TDate::Min( const TDate _BIDSFAR & dt ) const
  304. {
  305.     return dt.Julnum < Julnum ? dt : *this;
  306. }
  307.  
  308. //
  309. // Returns the month of this TDate.
  310. //
  311. MonthTy TDate::Month() const
  312. {
  313.     MonthTy m; DayTy d; YearTy y;
  314.     Mdy(m, d, y);
  315.     return m;
  316. }
  317.  
  318. //
  319. //
  320. //
  321. TDate TDate::Previous( const _TCHAR _BIDSFAR *dayName) const
  322. {
  323.     return Previous( DayOfWeek(dayName) );
  324. }
  325.  
  326. //
  327. //
  328. //
  329. TDate TDate::Previous( DayTy desiredDayOfWeek ) const
  330. {
  331.     //    Renumber the desired and current day of week to start at 0 (Monday)
  332.     //    and end at 6 (Sunday).
  333.  
  334.     desiredDayOfWeek--;
  335.     DayTy thisDayOfWeek = WeekDay() - 1;
  336.     JulTy j = Julnum;
  337.  
  338.     //    Have to determine how many days difference from current day back to
  339.     //    desired, if any.  Special calculation under the 'if' statement to
  340.     //    effect the wraparound counting from Monday (0) back to Sunday (6).
  341.  
  342.     if( desiredDayOfWeek > thisDayOfWeek )
  343.         thisDayOfWeek += 7 - desiredDayOfWeek;
  344.     else
  345.         thisDayOfWeek -= desiredDayOfWeek;
  346.     j -= thisDayOfWeek; // Adjust j to set it at the desired day of week.
  347.     return  TDate(j);
  348. }
  349.  
  350. DayTy TDate::WeekDay() const
  351. {
  352.     return DayTy(((((Julnum+1)%7)+6)%7)+1);
  353. }
  354.  
  355. //
  356. // Returns the year of this TDate.
  357. //
  358. YearTy TDate::Year() const
  359. {
  360.     MonthTy m; DayTy d; YearTy y;
  361.     Mdy(m, d, y);
  362.     return y;
  363. }
  364.